﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using HSS.Data;
using HSS.Forms;

namespace DuplicateFileExplorer
{
	public partial class Form1 : Form
	{
		#region Fields
		private FileSearcher searcher;
		
		//
		// Defect in DropDownMenuStrip
		// https://connect.microsoft.com/VisualStudio/feedback/details/282496/contextmenustrip-sourcecontrol-always-returns-null-for-items-in-sub-menus
		DataListView rightClickedListView; 
		//
		//

		#endregion

		#region Constructors
		/// <summary>
		/// Constructor
		/// </summary>
		public Form1()
		{
			InitializeComponent();
			InitializeColumns();
		}
		#endregion

		#region Methods
		void Search()
		{
			Cursor = Cursors.WaitCursor;

			this.lsvNonDuplicateFiles.Items.Clear();
			this.lsvFailedDirectories.Items.Clear();

			try
			{

				var duplicateFiles = new List<FileInfo>();
				var paths = new List<string>();

				if (string.IsNullOrEmpty(this.txtFolder1.Text))
				{
					MessageBox.Show("Missing Folder1 Path.");
					return;
				}
				if (!Directory.Exists(this.txtFolder1.Text))
				{
					MessageBox.Show("Folder1 [ " + this.txtFolder1.Text + " ] does not exist.");
					return;
				}
				paths.Add(this.txtFolder1.Text);

				if (this.chkIncludeFolder2.Checked)
				{
					if (string.IsNullOrEmpty(this.txtFolder2.Text))
					{
						MessageBox.Show("Missing Folder2 Path.");
						return;
					}
					if (!Directory.Exists(this.txtFolder2.Text))
					{
						MessageBox.Show("Folder2 [ " + this.txtFolder2.Text + " ] does not exist.");
						return;
					}
					paths.Add(this.txtFolder2.Text);
				}

				if (this.chkIncludeFolder3.Checked)
				{
					if (string.IsNullOrEmpty(this.txtFolder3.Text))
					{
						MessageBox.Show("Missing Folder3 path.");
						return;
					}
					if (!Directory.Exists(this.txtFolder3.Text))
					{
						MessageBox.Show("Folder3 [ " + this.txtFolder3.Text + " ] does not exist.");
						return;
					}
					paths.Add(this.txtFolder3.Text);
				}

				var patterns = this.txtExtensionFilter.Text.Split(";".ToCharArray()).ToList();
				var exclDirs = this.txtExcludeDirectories.Text.Split(";".ToCharArray()).ToList();
				var exclExts = this.txtExcludeExtensions.Text.Split(";".ToCharArray()).ToList();

				this.searcher = new FileSearcher();
				this.searcher.Canceled += new EventHandler<EventArgs>(Searcher_Canceled);
				this.searcher.Completed += new EventHandler<EventArgs>(Searcher_Completed);
				this.searcher.Errored += new EventHandler<ErroredEventArgs>(Searcher_Errored);
				this.searcher.SearchAsync(paths, patterns, this.chkInlcudeSubfolders.Checked, exclDirs, exclExts, this.chkCreatedAfter.Checked ? this.dtpCreatedAfter.Value : DateTime.MinValue, this.chkCreatedBefore.Checked ? this.dtpCreatedBefore.Value : DateTime.MaxValue, this.chkNewerThan.Checked ? this.dtpNewerThan.Value : DateTime.MinValue, this.chkOlderThan.Checked ? this.dtpOlderThan.Value : DateTime.MaxValue);

				this.btnCancelSearch.Enabled = true;
				this.stsProgress.Visible = true;
				this.btnSearch.Enabled = false;
				this.stsMessage.Text = "Searching ...";

			}
			catch (Exception ex)
			{
				if (null != searcher)
				{
					searcher.Canceled -= new EventHandler<EventArgs>(Searcher_Canceled);
					searcher.Completed -= new EventHandler<EventArgs>(Searcher_Completed);
					searcher.Errored -= new EventHandler<ErroredEventArgs>(Searcher_Errored);
					searcher = null;
				}
				this.btnCancelSearch.Enabled = false;
				this.stsProgress.Visible = false;
				this.btnSearch.Enabled = true;
				this.stsMessage.Text = ex.Message;
				MessageBox.Show(ex.Message);
			}
			finally
			{
				Cursor = Cursors.Default;
			}
		}
		void ProcessResults()
		{
			try
			{
				this.lstResults.LoadData(searcher.SearchResults);


				var duplicateNames = (from d in searcher.SearchResults
									  group d by d.Name into g
									  where g.Count() > 1
									  select g.Key).ToList();

				var notduplicateNames = (from d in searcher.SearchResults
										 group d by d.Name into g
										 where g.Count() == 1
										 select g.Key).ToList();

				var duplicates = searcher.SearchResults.Where(f => duplicateNames.Contains(f.Name)).ToList();
				this.lsvDuplicateFiles.LoadData(duplicates);

				var nonduplicates = searcher.SearchResults.Where(f => !duplicateNames.Contains(f.Name)).ToList();
				foreach (var item in nonduplicates.OrderBy(k => k.Name))
					AddEntry(item.Info, this.lsvNonDuplicateFiles);

				foreach (var item in this.searcher.FailedDirectories.OrderBy(k => k.Name).OrderBy(k => k.FullName))
					AddEntry(item, this.lsvFailedDirectories);

				this.stsTotalFileCount.Text = "Total Files: " + searcher.SearchResults.Count.ToString();
				this.stsDuplicateFileCount.Text = "Duplicate Files: " + this.lsvDuplicateFiles.Items.Count.ToString();
				this.stsNonDuplicateFileCount.Text = "Non-Duplicate Files: " + this.lsvNonDuplicateFiles.Items.Count.ToString();
				this.stsFailedDirectoryCount.Text = "Failed Directories: " + this.lsvFailedDirectories.Items.Count.ToString();

				this.btnSaveResults.Enabled = this.lstResults.Items.Count > 0;
				this.btnSaveDuplicates.Enabled = this.lsvDuplicateFiles.Items.Count > 0;
				this.btnSaveNonDuplicates.Enabled = this.lsvNonDuplicateFiles.Items.Count > 0;
				this.btnSaveFailedDirectories.Enabled = this.lsvFailedDirectories.Items.Count > 0;
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
			finally
			{
				if (this.searcher.HasError)
					MessageBox.Show("Search completed with errors" + Environment.NewLine + this.searcher.Error.Message);
				this.searcher.Canceled -= new EventHandler<EventArgs>(Searcher_Canceled);
				this.searcher.Completed -= new EventHandler<EventArgs>(Searcher_Completed);
				this.searcher.Errored -= new EventHandler<ErroredEventArgs>(Searcher_Errored);
				this.searcher = null;
				this.btnSearch.Enabled = true;
				this.btnCancelSearch.Enabled = false;
				this.stsProgress.Visible = false;
			}
		}
		void InitializeColumns()
		{
			#region DuplicateFiles View

			#region clmResultColumnCreatedDate
			this.clmResultColumnCreatedDate.ValueGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).CreationTime; };
			this.clmResultColumnCreatedDate.GroupKeyGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).CreationTime; };
			this.clmResultColumnCreatedDate.GroupKeyToTitleConverter = delegate(object groupKey) { return "Created Date: " + groupKey; };
			#endregion

			#region clmResultColumnName
			this.clmResultColumnName.ValueGetter = delegate(IDataContainer row) { return row.Name; };
			this.clmResultColumnName.GroupKeyGetter = delegate(IDataContainer row) { return row.Name; };
			this.clmResultColumnName.GroupKeyToTitleConverter = delegate(object groupKey) { return "File Name: " + groupKey; };
			#endregion

			#region clmResultColumnSize
			this.clmResultColumnSize.ValueGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).Size; };
			this.clmResultColumnSize.GroupKeyGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).Size; };
			this.clmResultColumnSize.GroupKeyToTitleConverter = delegate(object groupKey) { return "File Size: " + groupKey; };
			#endregion

			#region clmResultColumnFolder
			this.clmResultColumnFolder.ValueGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).DirectoryName; };
			this.clmResultColumnFolder.GroupKeyGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).DirectoryName; };
			this.clmResultColumnFolder.GroupKeyToTitleConverter = delegate(object groupKey) { return "Directory Name: " + groupKey; };
			#endregion

			#region clmResultColumnModifiedDate
			this.clmResultColumnModifiedDate.ValueGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).LastWriteTime; };
			this.clmResultColumnModifiedDate.GroupKeyGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).LastWriteTime; };
			this.clmResultColumnModifiedDate.GroupKeyToTitleConverter = delegate(object groupKey) { return "Modified Date: " + groupKey; };
			#endregion

			#endregion

			#region DuplicateFiles View

			#region clmDupeColumnCreatedDate
			this.clmDupeColumnCreatedDate.ValueGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).CreationTime; };
			this.clmDupeColumnCreatedDate.GroupKeyGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).CreationTime; };
			this.clmDupeColumnCreatedDate.GroupKeyToTitleConverter = delegate(object groupKey) { return "Created Date: " + groupKey; };
			#endregion

			#region clmDupeColumnName
			this.clmDupeColumnName.ValueGetter = delegate(IDataContainer row) { return row.Name; };
			this.clmDupeColumnName.GroupKeyGetter = delegate(IDataContainer row) { return row.Name; };
			this.clmDupeColumnName.GroupKeyToTitleConverter = delegate(object groupKey) { return "File Name: " + groupKey; };
			#endregion

			#region clmDupeColumnSize
			this.clmDupeColumnSize.ValueGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).Size; };
			this.clmDupeColumnSize.GroupKeyGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).Size; };
			this.clmDupeColumnSize.GroupKeyToTitleConverter = delegate(object groupKey) { return "File Size: " + groupKey; };
			#endregion

			#region clmDupeColumnFolder
			this.clmDupeColumnFolder.ValueGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).DirectoryName; };
			this.clmDupeColumnFolder.GroupKeyGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).DirectoryName; };
			this.clmDupeColumnFolder.GroupKeyToTitleConverter = delegate(object groupKey) { return "Directory Name: " + groupKey; };
			#endregion

			#region clmDupeColumnModifiedDate
			this.clmDupeColumnModifiedDate.ValueGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).LastWriteTime; };
			this.clmDupeColumnModifiedDate.GroupKeyGetter = delegate(IDataContainer row) { return ((FileSearchResultItem)row).LastWriteTime; };
			this.clmDupeColumnModifiedDate.GroupKeyToTitleConverter = delegate(object groupKey) { return "Modified Date: " + groupKey; };
			#endregion

			#endregion
		}

		static string GetFolder()
		{
			var result = string.Empty;
			using (var dlg = new FolderBrowserDialog())
			{
				dlg.Description = "Select Search Folder";
				if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
					result = dlg.SelectedPath;
			}
			return result;
		}
		static string GetFile()
		{
			var result = string.Empty;
			using (var dlg = new SaveFileDialog())
			{
				dlg.Filter = "Excel (*.csv)|*.csv|Text File (*.txt)|*.txt";
				if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
					result = dlg.FileName;
			}
			return result;
		}
		static void AddEntry(FileSystemInfo fileSystemInfo, ListView view)
		{
			var item = view.Items.Add(fileSystemInfo.Name);
			item.SubItems.Add(Path.GetDirectoryName(fileSystemInfo.FullName));
			item.SubItems.Add(fileSystemInfo.CreationTime.ToString());
			item.SubItems.Add(fileSystemInfo.LastWriteTime.ToString());
			if (fileSystemInfo is FileInfo)
				item.SubItems.Add((((FileInfo)fileSystemInfo).Length / 1024).ToString() + " KB");
		}
		static void ListViewToCSV(ListView listView, string filePath, bool includeHidden)
		{
			var result = new StringBuilder();
			WriteCSVRow(result, listView.Columns.Count, i => includeHidden || listView.Columns[i].Width > 0, i => listView.Columns[i].Text);
			foreach (ListViewItem listItem in listView.Items)
				WriteCSVRow(result, listView.Columns.Count, i => includeHidden || listView.Columns[i].Width > 0, i => listItem.SubItems[i].Text);
			File.WriteAllText(filePath, result.ToString());
		}
		static void WriteCSVRow(StringBuilder result, int itemsCount, Func<int, bool> isColumnNeeded, Func<int, string> columnValue)
		{
			bool isFirstTime = true;
			for (int i = 0; i < itemsCount; i++)
			{
				if (!isColumnNeeded(i))
					continue;
				if (!isFirstTime)
					result.Append(",");
				isFirstTime = false;
				result.Append(String.Format("\"{0}\"", columnValue(i)));
			}
			result.AppendLine();
		}
		static void BuildViewSortByMenu(ToolStripMenuItem mi, DataListView listView)
		{
			ToolStripMenuItem miChild;

			bool isChecked = false;
			foreach (DataListColumn col in listView.Columns)
			{
				miChild = mi.DropDownItems.Add(col.Text) as ToolStripMenuItem;
				if (!isChecked && listView.IsSorted)
				{
					isChecked = col.Index == listView.ArrangedBy && listView.SortOrder != SortOrder.None;
					miChild.Checked = isChecked;
				}
				miChild.Enabled = listView.AllowSort;
			}
			if (isChecked && listView.AllowSort)
			{
				miChild = mi.DropDownItems.Add("(None)") as ToolStripMenuItem;
				miChild.Enabled = listView.AllowSort;
			}

			mi.DropDownItems.Add("-");

			bool sorted = listView.AllowSort && listView.IsSorted && listView.SortOrder != SortOrder.None;
			miChild = mi.DropDownItems.Add("Ascending") as ToolStripMenuItem;
			miChild.Checked = sorted && listView.SortOrder == SortOrder.Ascending;
			miChild.Enabled = sorted;

			miChild = mi.DropDownItems.Add("Descending") as ToolStripMenuItem;
			miChild.Checked = sorted && listView.SortOrder == SortOrder.Descending;
			miChild.Enabled = sorted;

		}
		static void BuildViewGroupByMenu(ToolStripMenuItem mi, DataListView listView)
		{
			ToolStripMenuItem miChild;

			bool isChecked = false;
			foreach (DataListColumn col in listView.Columns)
			{
				miChild = mi.DropDownItems.Add(col.Text) as ToolStripMenuItem;
				if (!isChecked && listView.IsGrouped)
				{
					isChecked = col.Index == listView.ArrangedBy && listView.SortOrder != SortOrder.None;
					miChild.Checked = isChecked;
				}
				miChild.Enabled = listView.AllowShowGroups;
			}
			if (isChecked && listView.AllowShowGroups)
			{
				miChild = mi.DropDownItems.Add("(None)") as ToolStripMenuItem;
				miChild.Enabled = listView.AllowShowGroups;
			}

			mi.DropDownItems.Add("-");

			bool grouped = listView.AllowShowGroups && listView.IsGrouped && isChecked && listView.SortOrder != SortOrder.None;

			miChild = mi.DropDownItems.Add("Ascending") as ToolStripMenuItem;
			miChild.Checked = grouped && listView.SortOrder == SortOrder.Ascending;
			miChild.Enabled = grouped && listView.View != View.List;

			miChild = mi.DropDownItems.Add("Descending") as ToolStripMenuItem;
			miChild.Checked = grouped && listView.SortOrder == SortOrder.Descending;
			miChild.Enabled = grouped && listView.View != View.List;

		}

		#endregion

		#region Event Handlers

		private void chkIncludeFolder2_CheckedChanged(object sender, EventArgs e)
		{
			this.txtFolder2.Enabled = this.chkIncludeFolder2.Checked;
			this.btnSelectFolder2.Enabled = this.chkIncludeFolder2.Checked;
		}

		private void chkIncludeFolder3_CheckedChanged(object sender, EventArgs e)
		{
			this.txtFolder3.Enabled = this.chkIncludeFolder3.Checked;
			this.btnSelectFolder3.Enabled = this.chkIncludeFolder3.Checked;
		}

		private void chkCreatedAfter_CheckedChanged(object sender, EventArgs e)
		{
			this.dtpCreatedAfter.Enabled = this.chkCreatedAfter.Checked;
		}

		private void chkCreatedBefore_CheckedChanged(object sender, EventArgs e)
		{
			this.dtpCreatedBefore.Enabled = this.chkCreatedBefore.Checked;
		}

		private void chkNewerThan_CheckedChanged(object sender, EventArgs e)
		{
			this.dtpNewerThan.Enabled = this.chkNewerThan.Checked;
		}

		private void chkOlderThan_CheckedChanged(object sender, EventArgs e)
		{
			this.dtpOlderThan.Enabled = this.chkOlderThan.Checked;
		}

		private void btnSelectFolder1_Click(object sender, EventArgs e)
		{
			this.txtFolder1.Text = GetFolder();
		}

		private void btnSelectFolder2_Click(object sender, EventArgs e)
		{
			this.txtFolder2.Text = GetFolder();
		}

		private void btnSelectFolder3_Click(object sender, EventArgs e)
		{
			this.txtFolder3.Text = GetFolder();
		}

		private void btnSaveResults_Click(object sender, EventArgs e)
		{
			var filePath = GetFile();
			if (!string.IsNullOrEmpty(filePath))
				ListViewToCSV(this.lstResults, filePath, true);
		}

		private void btnSaveDuplicates_Click(object sender, EventArgs e)
		{
			var filePath = GetFile();
			if (!string.IsNullOrEmpty(filePath))
				ListViewToCSV(this.lsvDuplicateFiles, filePath, true);
		}

		private void btnSaveNonDuplicates_Click(object sender, EventArgs e)
		{
			var filePath = GetFile();
			if (!string.IsNullOrEmpty(filePath))
				ListViewToCSV(this.lsvNonDuplicateFiles, filePath, true);
		}

		private void btnSaveFailedDirectories_Click(object sender, EventArgs e)
		{
			var filePath = GetFile();
			if (!string.IsNullOrEmpty(filePath))
				ListViewToCSV(this.lsvFailedDirectories, filePath, true);
		}

		private void btnSearch_Click(object sender, EventArgs e)
		{
			this.Search();
		}

		private void btnCancelSearch_Click(object sender, EventArgs e)
		{
			this.btnCancelSearch.Enabled = false;
			this.stsMessage.Text = "Cancelling the search ...";
			searcher.CancelAsync();
		}

		private void Searcher_Errored(object sender, ErroredEventArgs e)
		{
			var str = new StringBuilder();
			str.AppendLine("Error encountered: " + e.Error.Message);
			str.AppendLine("Current Directory: " + e.CurrentDirectory);
			str.AppendLine("Current Pattern: " + e.CurrentSearchPattern);
			str.AppendLine();
			str.AppendLine("Cancel the search?");

			e.Cancel = false;
			if (MessageBox.Show(str.ToString(), e.CurrentDirectory, MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
				e.Cancel = true;
		}

		private void Searcher_Completed(object sender, EventArgs e)
		{
			if (this.searcher.HasError)
			{
				this.stsMessage.Text = "The search has completed with an error.";
				MessageBox.Show("The search has completed, but an error was encountered." + Environment.NewLine + this.searcher.Error.Message);
			}
			else
				this.stsMessage.Text = "The search has completed.";
			this.ProcessResults();
		}

		private void Searcher_Canceled(object sender, EventArgs e)
		{
			if (this.searcher.HasError)
				this.stsMessage.Text = "The search was cancelled, and an error was encountered." + Environment.NewLine + this.searcher.Error.Message;
			else
				this.stsMessage.Text = "The search was cancelled.";

			MessageBox.Show("The search was cancelled.");
			this.ProcessResults();
		}

		private void btnOpenFolderLocation_Click(object sender, EventArgs e)
		{
			if (this.lstResults.SelectedItems.Count > 0 && null != this.lstResults.SelectedItems[0])
			{
				var path = this.lstResults.SelectedItems[0].SubItems[1].Text;
				System.Diagnostics.Process.Start(path);
			}
		}

		private void btnOpenFolderLocation1_Click(object sender, EventArgs e)
		{
			if (this.lsvDuplicateFiles.SelectedItems.Count > 0 && null != this.lsvDuplicateFiles.SelectedItems[0])
			{
				var path = this.lsvDuplicateFiles.SelectedItems[0].SubItems[1].Text;
				System.Diagnostics.Process.Start(path);
			}
		}

		private void btnOpenFolderLocation2_Click(object sender, EventArgs e)
		{
			if (this.lsvNonDuplicateFiles.SelectedItems.Count > 0 && null != this.lsvNonDuplicateFiles.SelectedItems[0])
			{
				var path = this.lsvNonDuplicateFiles.SelectedItems[0].SubItems[1].Text;
				System.Diagnostics.Process.Start(path);
			}
		}

		private void btnOpenFolderLocation3_Click(object sender, EventArgs e)
		{
			if (this.lsvFailedDirectories.SelectedItems.Count > 0 && null != this.lsvFailedDirectories.SelectedItems[0])
			{
				var path = this.lsvFailedDirectories.SelectedItems[0].SubItems[1].Text;
				System.Diagnostics.Process.Start(path);
			}
		}

		private void lstResults_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.btnOpenFolderLocation.Enabled = this.lstResults.SelectedItems.Count > 0;
		}

		private void lsvDuplicateFiles_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.btnOpenFolderLocation1.Enabled = this.lsvDuplicateFiles.SelectedItems.Count > 0;
		}

		private void lsvNonDuplicateFiles_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.btnOpenFolderLocation2.Enabled = this.lsvNonDuplicateFiles.SelectedItems.Count > 0;
		}

		private void lsvFailedDirectories_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.btnOpenFolderLocation3.Enabled = this.lsvFailedDirectories.SelectedItems.Count > 0;
		}

		private void ctxDuplicateFileContextMenu_Opening(object sender, CancelEventArgs e)
		{
			if (this.lsvDuplicateFiles.Items.Count == 0)
				return;

			rightClickedListView = this.ctxListViewContextMenu.SourceControl as DataListView;
			if (null == rightClickedListView)
				return;

			#region Arrange By - Column Name

			this.mnuSortBy.DropDownItems.Clear();
			BuildViewSortByMenu(this.mnuSortBy, rightClickedListView);
			this.mnuSortBy.Visible = true;

			this.mnuGroupBy.DropDownItems.Clear();
			BuildViewGroupByMenu(this.mnuGroupBy, rightClickedListView);
			this.mnuGroupBy.Visible = true;

			#endregion

			e.Cancel = false;
		}
		
		private void lsvDuplicateFiles_SortBy(object sender, ToolStripItemClickedEventArgs e)
		{
			if (!(e.ClickedItem is ToolStripMenuItem))
				return;

			if (null == rightClickedListView)
				return;

			// At this point in time, even though the user Clicked the
			// the menu item, it is not currently toBeChecked, so
			// if it is not checked that means the request is to act as if it
			// is checked or more accurately will be checked.			
			bool Checked = !((ToolStripMenuItem)e.ClickedItem).Checked;
			if (Checked)
			{
				// The Menu Item Clicked
				string text = e.ClickedItem.Text;

				switch (text)
				{
					case "Ascending":
						rightClickedListView.SortOrder = SortOrder.Ascending;
						rightClickedListView.Sort(rightClickedListView.ArrangedBy);
						break;

					case "Descending":
						rightClickedListView.SortOrder = SortOrder.Descending;
						rightClickedListView.Sort(rightClickedListView.ArrangedBy);
						break;

					default:
						// Look for the Column Name matching the Menu Item
						// and if found, then Arrange (Sort) the Groups (Columns) by the
						// Column (Group) requested
						int colIndex = 0;
						DataListColumn col = null;
						if (text == "(None)")
						{
							rightClickedListView.SortOrder = SortOrder.None;
							rightClickedListView.IsSorted = false;
						}
						else
						{
							col = rightClickedListView.Columns[text] as DataListColumn;
							if (null != col) colIndex = col.Index;
							rightClickedListView.Sort(colIndex);
						}
						break;
				}
			}
		}
		
		private void lsvDuplicateFiles_GroupBy(object sender, ToolStripItemClickedEventArgs e)
		{
			if (!(e.ClickedItem is ToolStripMenuItem))
				return;

			if (null == rightClickedListView)
				return;

			// At this point in time, even though the user Clicked the
			// the menu item, it is not currently toBeChecked, so
			// if it is not checked that means the request is to act as if it
			// is checked or more accurately will be checked.			
			bool toBeChecked = !((ToolStripMenuItem)e.ClickedItem).Checked;
			if (toBeChecked)
			{
				// The Menu Item Clicked
				string text = e.ClickedItem.Text;

				switch (text)
				{
					case "Ascending":
						rightClickedListView.SortOrder = SortOrder.Ascending;
						rightClickedListView.Group(rightClickedListView.ArrangedBy);
						break;

					case "Descending":
						rightClickedListView.SortOrder = SortOrder.Descending;
						rightClickedListView.Group(rightClickedListView.ArrangedBy);
						break;

					default:
						// Look for the Column Name matching the Menu Item
						// and if found, then Arrange (Sort) the Groups (Columns) by the
						// Column (Group) requested
						int colIndex = 0;
						DataListColumn col = null;
						if (text == "(None)")
						{
							rightClickedListView.SortOrder = SortOrder.None;
							rightClickedListView.IsGrouped = false;
						}
						else
						{
							col = rightClickedListView.Columns[text] as DataListColumn;
							if (null != col) colIndex = col.Index;
							rightClickedListView.Group(colIndex);
						}
						break;
				}
			}
		}

		#endregion
	}
}
